{
 "cells": [
  {
   "cell_type": "code",
   "id": "17c1056a",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-07-22T07:59:52.478202Z",
     "start_time": "2025-07-22T07:59:15.384498Z"
    }
   },
   "source": [
    "import os  # 导入操作系统模块，用于文件路径操作\n",
    "import json  # 导入JSON模块，用于处理JSON数据\n",
    "import requests  # 导入HTTP请求库，用于API调用\n",
    "import numpy as np  # 导入NumPy库，用于数值计算\n",
    "from typing import List, Dict, Any, Optional  # 导入类型提示\n",
    "from dataclasses import dataclass  # 导入数据类装饰器\n",
    "import pickle  # 导入pickle模块，用于序列化对象\n",
    "import re  # 导入正则表达式模块\n",
    "from pathlib import Path  # 导入Path类，用于路径操作\n",
    "\n",
    "# 使用 OpenAI embeddings 或 Hugging Face transformers 作为替代\n",
    "try:\n",
    "    from sentence_transformers import SentenceTransformer  # 尝试导入sentence_transformers库\n",
    "    USE_SENTENCE_TRANSFORMERS = True  # 设置标志表示可以使用sentence_transformers\n",
    "except ImportError:\n",
    "    USE_SENTENCE_TRANSFORMERS = False  # 设置标志表示不能使用sentence_transformers\n",
    "    # 备用方案：使用 Hugging Face transformers\n",
    "    try:\n",
    "        from transformers import AutoTokenizer, AutoModel  # 尝试导入transformers库\n",
    "        import torch  # 导入PyTorch库\n",
    "        USE_TRANSFORMERS = True  # 设置标志表示可以使用transformers\n",
    "    except ImportError:\n",
    "        USE_TRANSFORMERS = False  # 设置标志表示不能使用transformers\n",
    "\n",
    "import faiss  # 导入FAISS库，用于向量检索\n",
    "\n",
    "@dataclass\n",
    "class Document:\n",
    "    \"\"\"文档数据结构\"\"\"\n",
    "    id: str  # 文档唯一标识符\n",
    "    content: str  # 文档内容\n",
    "    metadata: Dict[str, Any] = None  # 文档元数据，默认为None\n",
    "    embedding: Optional[np.ndarray] = None  # 文档的嵌入向量，默认为None\n",
    "\n",
    "class DeepSeekClient:\n",
    "    \"\"\"DeepSeek API客户端,向DeepSeek API发送请求\"\"\"\n",
    "    \n",
    "    def __init__(self, api_key: str, base_url: str = \"https://api.deepseek.com\"):\n",
    "        self.api_key = api_key  # 存储API密钥\n",
    "        self.base_url = base_url  # 存储API基础URL\n",
    "        self.headers = {  # 设置HTTP请求头\n",
    "            \"Authorization\": f\"Bearer {api_key}\",  # 添加认证信息\n",
    "            \"Content-Type\": \"application/json\"  # 设置内容类型\n",
    "        }\n",
    "    \n",
    "    def chat_completion(self, messages: List[Dict[str, str]], \n",
    "                       model: str = \"deepseek-chat\", \n",
    "                       max_tokens: int = 2048,\n",
    "                       temperature: float = 0.7) -> str:\n",
    "        \"\"\"调用DeepSeek聊天完成API\"\"\"\n",
    "        url = f\"{self.base_url}/chat/completions\"  # 构建API端点URL\n",
    "        \n",
    "        payload = {  # 构建请求负载\n",
    "            \"model\": model,  # 指定模型\n",
    "            \"messages\": messages,  # 设置消息列表\n",
    "            \"max_tokens\": max_tokens,  # 设置最大生成token数\n",
    "            \"temperature\": temperature,  # 设置温度参数\n",
    "            \"stream\": False  # 不使用流式响应\n",
    "        }\n",
    "        \n",
    "        try:\n",
    "            response = requests.post(url, headers=self.headers, json=payload)  # 发送POST请求\n",
    "            response.raise_for_status()  # 检查HTTP响应状态\n",
    "            \n",
    "            result = response.json()  # 解析JSON响应\n",
    "            return result[\"choices\"][0][\"message\"][\"content\"]  # 返回生成的内容\n",
    "        \n",
    "        except requests.exceptions.RequestException as e:\n",
    "            print(f\"API请求错误: {e}\")  # 打印API请求错误\n",
    "            return \"\"  # 返回空字符串\n",
    "        except KeyError as e:\n",
    "            print(f\"响应解析错误: {e}\")  # 打印响应解析错误\n",
    "            return \"\"  # 返回空字符串\n",
    "\n",
    "class DocumentProcessor:\n",
    "    \"\"\"文档处理器,将文档分割成块\"\"\"\n",
    "    \n",
    "    def __init__(self, chunk_size: int = 512, chunk_overlap: int = 50):\n",
    "        self.chunk_size = chunk_size  # 设置文本块大小\n",
    "        self.chunk_overlap = chunk_overlap  # 设置文本块重叠大小\n",
    "    \n",
    "    def load_text_file(self, file_path: str) -> str:\n",
    "        \"\"\"加载文本文件\"\"\"\n",
    "        with open(file_path, 'r', encoding='utf-8') as f:  # 打开文件\n",
    "            return f.read()  # 读取文件内容\n",
    "    \n",
    "    def split_text(self, text: str) -> List[str]:\n",
    "        \"\"\"将文本分割成块\"\"\"\n",
    "        # 按段落分割\n",
    "        paragraphs = re.split(r'\\n\\s*\\n', text)  # 使用正则表达式按段落分割文本\n",
    "        \n",
    "        chunks = []  # 初始化文本块列表\n",
    "        current_chunk = \"\"  # 初始化当前文本块\n",
    "        \n",
    "        for paragraph in paragraphs:  # 遍历每个段落\n",
    "            # 如果当前块加上新段落超过限制，保存当前块\n",
    "            if len(current_chunk) + len(paragraph) > self.chunk_size:  # 检查是否超过块大小限制\n",
    "                if current_chunk:  # 如果当前块不为空\n",
    "                    chunks.append(current_chunk.strip())  # 添加当前块到列表\n",
    "                current_chunk = paragraph  # 开始新的块\n",
    "            else:\n",
    "                current_chunk += \"\\n\\n\" + paragraph if current_chunk else paragraph  # 将段落添加到当前块\n",
    "        \n",
    "        # 添加最后一块\n",
    "        if current_chunk:  # 如果最后一块不为空\n",
    "            chunks.append(current_chunk.strip())  # 添加到列表\n",
    "        \n",
    "        return chunks  # 返回文本块列表\n",
    "    \n",
    "    def process_file(self, file_path: str) -> List[Document]:\n",
    "        \"\"\"处理单个文件\"\"\"\n",
    "        text = self.load_text_file(file_path)  # 加载文件内容\n",
    "        chunks = self.split_text(text)  # 分割文本\n",
    "        \n",
    "        documents = []  # 初始化文档列表\n",
    "        filename = Path(file_path).name  # 获取文件名\n",
    "        \n",
    "        for i, chunk in enumerate(chunks):  # 遍历每个文本块\n",
    "            doc = Document(  # 创建文档对象\n",
    "                id=f\"{filename}_{i}\",  # 设置文档ID\n",
    "                content=chunk,  # 设置文档内容\n",
    "                metadata={  # 设置文档元数据\n",
    "                    \"source\": filename,  # 源文件名\n",
    "                    \"chunk_id\": i,  # 块ID\n",
    "                    \"file_path\": file_path  # 文件路径\n",
    "                }\n",
    "            )\n",
    "            documents.append(doc)  # 添加文档到列表\n",
    "        \n",
    "        return documents  # 返回文档列表\n",
    "\n",
    "class EmbeddingModel:\n",
    "    \"\"\"嵌入模型包装器，主要作用是把文本变为稠密向量\"\"\"\n",
    "    \n",
    "    def __init__(self, model_name: str = \"all-MiniLM-L6-v2\"):\n",
    "        \"\"\"\n",
    "        all-MiniLM-L6-v2模型尺寸\n",
    "        \"\"\"\n",
    "        self.model_name = model_name  # 存储模型名称\n",
    "        self.model = None  # 初始化模型为None\n",
    "        self.tokenizer = None  # 初始化分词器为None\n",
    "        self._initialize_model()  # 初始化模型\n",
    "    \n",
    "    def _initialize_model(self):\n",
    "        \"\"\"初始化嵌入模型\"\"\"\n",
    "        if USE_SENTENCE_TRANSFORMERS:  # 如果可以使用sentence_transformers\n",
    "            try:\n",
    "                self.model = SentenceTransformer(self.model_name)  # 加载sentence_transformers模型\n",
    "                self.model_type = \"sentence_transformers\"  # 设置模型类型\n",
    "                print(f\"使用 sentence-transformers 模型: {self.model_name}\")  # 打印使用的模型\n",
    "            except Exception as e:\n",
    "                print(f\"sentence-transformers 初始化失败: {e}\")  # 打印初始化失败信息\n",
    "                self._fallback_to_transformers()  # 回退到transformers\n",
    "        else:\n",
    "            self._fallback_to_transformers()  # 回退到transformers\n",
    "    \n",
    "    def _fallback_to_transformers(self):\n",
    "        \"\"\"回退到 transformers 库\"\"\"\n",
    "        if USE_TRANSFORMERS:  # 如果可以使用transformers\n",
    "            try:\n",
    "                # 使用更简单的模型\n",
    "                model_name = \"sentence-transformers/all-MiniLM-L6-v2\"  # 设置模型名称\n",
    "                self.tokenizer = AutoTokenizer.from_pretrained(model_name)  # 加载分词器\n",
    "                self.model = AutoModel.from_pretrained(model_name)  # 加载模型\n",
    "                self.model_type = \"transformers\"  # 设置模型类型\n",
    "                print(f\"使用 transformers 模型: {model_name}\")  # 打印使用的模型\n",
    "            except Exception as e:\n",
    "                print(f\"transformers 初始化失败: {e}\")  # 打印初始化失败信息\n",
    "                self._fallback_to_simple()  # 回退到简单方法\n",
    "        else:\n",
    "            self._fallback_to_simple()  # 回退到简单方法\n",
    "    \n",
    "    def _fallback_to_simple(self):\n",
    "        \"\"\"回退到简单的嵌入方法\"\"\"\n",
    "        print(\"回退到简单的 TF-IDF 嵌入方法\")  # 打印回退信息\n",
    "        self.model_type = \"tfidf\"  # 设置模型类型\n",
    "        try:\n",
    "            from sklearn.feature_extraction.text import TfidfVectorizer  # 导入TF-IDF向量化器\n",
    "            self.model = TfidfVectorizer(max_features=384, stop_words='english')  # 创建TF-IDF向量化器\n",
    "            self.fitted = False  # 设置未拟合标志\n",
    "        except ImportError:\n",
    "            print(\"警告: sklearn 未安装，使用随机嵌入\")  # 打印警告\n",
    "            self.model_type = \"random\"  # 设置模型类型为随机\n",
    "    \n",
    "    def encode(self, texts: List[str], show_progress_bar: bool = True) -> np.ndarray:\n",
    "        \"\"\"编码文本为嵌入向量\"\"\"\n",
    "        if self.model_type == \"sentence_transformers\":  # 如果使用sentence_transformers\n",
    "            return self.model.encode(texts, show_progress_bar=show_progress_bar)  # 使用模型编码文本\n",
    "        \n",
    "        elif self.model_type == \"transformers\":  # 如果使用transformers\n",
    "            return self._encode_with_transformers(texts)  # 使用transformers编码\n",
    "        \n",
    "        elif self.model_type == \"tfidf\":  # 如果使用TF-IDF\n",
    "            return self._encode_with_tfidf(texts)  # 使用TF-IDF编码\n",
    "        \n",
    "        else:  # random\n",
    "            return self._encode_random(texts)  # 使用随机编码\n",
    "    \n",
    "    def _encode_with_transformers(self, texts: List[str]) -> np.ndarray:\n",
    "        \"\"\"使用 transformers 编码\"\"\"\n",
    "        embeddings = []  # 初始化嵌入列表\n",
    "        \n",
    "        for text in texts:  # 遍历每个文本\n",
    "            inputs = self.tokenizer(text, return_tensors=\"pt\", truncation=True, padding=True, max_length=512)  # 对文本进行分词\n",
    "            \n",
    "            with torch.no_grad():  # 不计算梯度\n",
    "                outputs = self.model(**inputs)  # 获取模型输出\n",
    "                # 使用 [CLS] token 的嵌入或平均池化\n",
    "                embedding = outputs.last_hidden_state.mean(dim=1).squeeze().numpy()  # 计算嵌入向量\n",
    "                embeddings.append(embedding)  # 添加到列表\n",
    "        \n",
    "        return np.array(embeddings)  # 返回嵌入向量数组\n",
    "    \n",
    "    def _encode_with_tfidf(self, texts: List[str]) -> np.ndarray:\n",
    "        \"\"\"使用 TF-IDF 编码\"\"\"\n",
    "        if not self.fitted:  # 如果模型未拟合\n",
    "            self.model.fit(texts)  # 拟合模型\n",
    "            self.fitted = True  # 设置已拟合标志\n",
    "        \n",
    "        return self.model.transform(texts).toarray()  # 转换文本并返回数组\n",
    "    \n",
    "    def _encode_random(self, texts: List[str]) -> np.ndarray:\n",
    "        \"\"\"随机嵌入（仅用于测试）\"\"\"\n",
    "        print(\"警告: 使用随机嵌入，结果可能不准确\")  # 打印警告\n",
    "        return np.random.randn(len(texts), 384)  # 返回随机嵌入向量\n",
    "\n",
    "class VectorStore:\n",
    "    \"\"\"向量存储和检索，主要作用是存储和检索文本的向量表示\"\"\"\n",
    "    \n",
    "    def __init__(self, embedding_model_name: str = \"all-MiniLM-L6-v2\"):\n",
    "        \"\"\"\n",
    "        初始化向量存储\n",
    "        \"\"\"\n",
    "        self.embedding_model = EmbeddingModel(embedding_model_name)  # 创建嵌入模型\n",
    "        self.documents: List[Document] = []  # 初始化文档列表\n",
    "        self.index = None  # 初始化索引为None\n",
    "        self.dimension = None  # 初始化维度为None\n",
    "    \n",
    "    def add_documents(self, documents: List[Document]):\n",
    "        \"\"\"添加文档到向量存储\"\"\"\n",
    "        print(f\"正在处理 {len(documents)} 个文档...\")  # 打印处理信息\n",
    "        \n",
    "        # 生成嵌入向量\n",
    "        contents = [doc.content for doc in documents]  # 提取文档内容\n",
    "        embeddings = self.embedding_model.encode(contents, show_progress_bar=True)  # 编码文档内容\n",
    "        \n",
    "        # 添加嵌入向量到文档\n",
    "        for doc, embedding in zip(documents, embeddings):  # 遍历文档和嵌入向量\n",
    "            doc.embedding = embedding  # 设置文档的嵌入向量\n",
    "        \n",
    "        self.documents.extend(documents)  # 将文档添加到列表\n",
    "        \n",
    "        # 构建FAISS索引\n",
    "        self._build_index()  # 构建索引\n",
    "        \n",
    "        print(f\"成功添加 {len(documents)} 个文档\")  # 打印成功信息\n",
    "    \n",
    "    def _build_index(self):\n",
    "        \"\"\"构建FAISS索引\"\"\"\n",
    "        if not self.documents:  # 如果没有文档\n",
    "            return  # 直接返回\n",
    "        \n",
    "        embeddings = np.array([doc.embedding for doc in self.documents])  # 获取所有嵌入向量\n",
    "        self.dimension = embeddings.shape[1]  # 设置维度\n",
    "        \n",
    "        # 创建FAISS索引\n",
    "        self.index = faiss.IndexFlatIP(self.dimension)  # 内积相似度\n",
    "        \n",
    "        # 标准化向量（用于余弦相似度）\n",
    "        faiss.normalize_L2(embeddings)  # L2标准化\n",
    "        self.index.add(embeddings.astype(np.float32))  # 添加向量到索引\n",
    "    \n",
    "    def search(self, query: str, top_k: int = 5) -> List[Document]:\n",
    "        \"\"\"搜索相关文档\"\"\"\n",
    "        if not self.index:  # 如果索引不存在\n",
    "            return []  # 返回空列表\n",
    "        \n",
    "        # 生成查询向量\n",
    "        query_embedding = self.embedding_model.encode([query])  # 编码查询\n",
    "        faiss.normalize_L2(query_embedding)  # L2标准化\n",
    "        \n",
    "        # 搜索\n",
    "        scores, indices = self.index.search(query_embedding.astype(np.float32), top_k)  # 执行搜索\n",
    "        \n",
    "        # 返回相关文档\n",
    "        results = []  # 初始化结果列表\n",
    "        for score, idx in zip(scores[0], indices[0]):  # 遍历分数和索引\n",
    "            if idx < len(self.documents):  # 如果索引有效\n",
    "                doc = self.documents[idx]  # 获取文档\n",
    "                results.append(doc)  # 添加到结果\n",
    "        \n",
    "        return results  # 返回结果\n",
    "    \n",
    "    def save(self, file_path: str):\n",
    "        \"\"\"保存向量存储\"\"\"\n",
    "        data = {  # 创建数据字典\n",
    "            'documents': self.documents,  # 存储文档\n",
    "            'dimension': self.dimension  # 存储维度\n",
    "        }\n",
    "        \n",
    "        with open(file_path, 'wb') as f:  # 打开文件\n",
    "            pickle.dump(data, f)  # 序列化数据\n",
    "        \n",
    "        # 保存FAISS索引\n",
    "        if self.index:  # 如果索引存在\n",
    "            faiss.write_index(self.index, file_path + \".faiss\")  # 写入索引\n",
    "    \n",
    "    def load(self, file_path: str):\n",
    "        \"\"\"加载向量存储\"\"\"\n",
    "        with open(file_path, 'rb') as f:  # 打开文件\n",
    "            data = pickle.load(f)  # 加载数据\n",
    "        \n",
    "        self.documents = data['documents']  # 设置文档\n",
    "        self.dimension = data['dimension']  # 设置维度\n",
    "        \n",
    "        # 加载FAISS索引\n",
    "        if os.path.exists(file_path + \".faiss\"):  # 如果索引文件存在\n",
    "            self.index = faiss.read_index(file_path + \".faiss\")  # 读取索引\n",
    "\n",
    "class RAGSystem:\n",
    "    \"\"\"RAG系统主类，主要作用是提供RAG系统的核心功能\"\"\"\n",
    "    \n",
    "    def __init__(self, deepseek_api_key: str, embedding_model: str = \"all-MiniLM-L6-v2\"):\n",
    "        self.deepseek_client = DeepSeekClient(deepseek_api_key)  # 创建DeepSeek客户端\n",
    "        self.document_processor = DocumentProcessor()  # 创建文档处理器\n",
    "        self.vector_store = VectorStore(embedding_model)  # 创建向量存储\n",
    "        self.conversation_history = []  # 初始化对话历史\n",
    "    \n",
    "    def add_documents_from_files(self, file_paths: List[str]):\n",
    "        \"\"\"从文件添加文档\"\"\"\n",
    "        all_documents = []  # 初始化文档列表\n",
    "        \n",
    "        for file_path in file_paths:  # 遍历文件路径\n",
    "            print(f\"处理文件: {file_path}\")  # 打印处理信息\n",
    "            documents = self.document_processor.process_file(file_path)  # 处理文件\n",
    "            all_documents.extend(documents)  # 添加文档到列表\n",
    "        \n",
    "        self.vector_store.add_documents(all_documents)  # 将文档添加到向量存储\n",
    "    \n",
    "    def add_documents_from_text(self, texts: List[str], metadata_list: List[Dict] = None):\n",
    "        \"\"\"从文本添加文档\"\"\"\n",
    "        documents = []  # 初始化文档列表\n",
    "        \n",
    "        for i, text in enumerate(texts):  # 遍历文本\n",
    "            chunks = self.document_processor.split_text(text)  # 分割文本\n",
    "            \n",
    "            for j, chunk in enumerate(chunks):  # 遍历文本块\n",
    "                doc = Document(  # 创建文档\n",
    "                    id=f\"text_{i}_{j}\",  # 设置ID\n",
    "                    content=chunk,  # 设置内容\n",
    "                    metadata=metadata_list[i] if metadata_list else {\"source\": f\"text_{i}\"}  # 设置元数据\n",
    "                )\n",
    "                documents.append(doc)  # 添加文档到列表\n",
    "        \n",
    "        self.vector_store.add_documents(documents)  # 将文档添加到向量存储\n",
    "    \n",
    "    def _build_context(self, relevant_docs: List[Document]) -> str:\n",
    "        \"\"\"构建上下文\"\"\"\n",
    "        context_parts = []  # 初始化上下文部分列表\n",
    "        \n",
    "        for i, doc in enumerate(relevant_docs):  # 遍历相关文档\n",
    "            context_parts.append(f\"文档 {i+1}:\")  # 添加文档标题\n",
    "            context_parts.append(doc.content)  # 添加文档内容\n",
    "            context_parts.append(\"\")  # 空行分隔\n",
    "        \n",
    "        return \"\\n\".join(context_parts)  # 连接上下文部分\n",
    "    \n",
    "    def _build_prompt(self, query: str, context: str) -> str:\n",
    "        \"\"\"构建提示词\"\"\"\n",
    "        prompt = f\"\"\"你是一个专业的AI助手。请根据以下上下文信息回答用户的问题。\n",
    "\n",
    "上下文信息：\n",
    "{context}\n",
    "\n",
    "用户问题：{query}\n",
    "\n",
    "请基于提供的上下文信息给出准确、详细的回答。如果上下文信息不足以回答问题，请说明这一点。\n",
    "\n",
    "回答：\"\"\"  # 构建提示词模板\n",
    "        \n",
    "        return prompt  # 返回提示词\n",
    "    \n",
    "    def query(self, question: str, top_k: int = 5, use_history: bool = False) -> Dict[str, Any]:\n",
    "        \"\"\"查询RAG系统\"\"\"\n",
    "        # 检索相关文档\n",
    "        relevant_docs = self.vector_store.search(question, top_k)  # 搜索相关文档\n",
    "        \n",
    "        if not relevant_docs:  # 如果没有找到相关文档\n",
    "            return {  # 返回错误信息\n",
    "                \"answer\": \"抱歉，我没有找到相关的文档来回答您的问题。\",\n",
    "                \"sources\": [],\n",
    "                \"context\": \"\"\n",
    "            }\n",
    "        \n",
    "        # 构建上下文\n",
    "        context = self._build_context(relevant_docs)  # 构建上下文\n",
    "        \n",
    "        # 构建消息\n",
    "        messages = []  # 初始化消息列表\n",
    "        \n",
    "        # 添加历史对话（如果需要）\n",
    "        if use_history:  # 如果使用历史\n",
    "            messages.extend(self.conversation_history)  # 添加对话历史\n",
    "        \n",
    "        # 添加当前查询\n",
    "        prompt = self._build_prompt(question, context)  # 构建提示词\n",
    "        messages.append({\"role\": \"user\", \"content\": prompt})  # 添加用户消息\n",
    "        print(messages)\n",
    "        # 调用DeepSeek API\n",
    "        answer = self.deepseek_client.chat_completion(messages)  # 获取回答\n",
    "        \n",
    "        # 更新对话历史\n",
    "        if use_history:  # 如果使用历史\n",
    "            self.conversation_history.append({\"role\": \"user\", \"content\": question})  # 添加用户问题\n",
    "            self.conversation_history.append({\"role\": \"assistant\", \"content\": answer})  # 添加助手回答\n",
    "            \n",
    "            # 限制历史长度\n",
    "            if len(self.conversation_history) > 10:  # 如果历史超过10条\n",
    "                self.conversation_history = self.conversation_history[-10:]  # 保留最近10条\n",
    "        \n",
    "        # 提取来源信息\n",
    "        sources = []  # 初始化来源列表\n",
    "        for doc in relevant_docs:  # 遍历相关文档\n",
    "            source_info = {  # 创建来源信息\n",
    "                \"document_id\": doc.id,  # 文档ID\n",
    "                \"content_preview\": doc.content[:200] + \"...\" if len(doc.content) > 200 else doc.content,  # 内容预览\n",
    "                \"metadata\": doc.metadata  # 元数据\n",
    "            }\n",
    "            sources.append(source_info)  # 添加来源信息\n",
    "        \n",
    "        return {  # 返回结果\n",
    "            \"answer\": answer,  # 回答\n",
    "            \"sources\": sources,  # 来源\n",
    "            \"context\": context,  # 上下文\n",
    "            \"relevant_documents\": len(relevant_docs)  # 相关文档数量\n",
    "        }\n",
    "    \n",
    "    def clear_history(self):\n",
    "        \"\"\"清除对话历史\"\"\"\n",
    "        self.conversation_history = []  # 重置对话历史\n",
    "    \n",
    "    def save_system(self, file_path: str):\n",
    "        \"\"\"保存RAG系统\"\"\"\n",
    "        self.vector_store.save(file_path)  # 保存向量存储\n",
    "        \n",
    "        # 保存对话历史\n",
    "        history_path = file_path + \".history\"  # 设置历史文件路径\n",
    "        with open(history_path, 'w', encoding='utf-8') as f:  # 打开文件\n",
    "            json.dump(self.conversation_history, f, ensure_ascii=False, indent=2)  # 保存对话历史\n",
    "    \n",
    "    def load_system(self, file_path: str):\n",
    "        \"\"\"加载RAG系统\"\"\"\n",
    "        self.vector_store.load(file_path)  # 加载向量存储\n",
    "        \n",
    "        # 加载对话历史\n",
    "        history_path = file_path + \".history\"  # 设置历史文件路径\n",
    "        if os.path.exists(history_path):  # 如果历史文件存在\n",
    "            with open(history_path, 'r', encoding='utf-8') as f:  # 打开文件\n",
    "                self.conversation_history = json.load(f)  # 加载对话历史\n",
    "\n",
    "def main():\n",
    "    \"\"\"主函数示例\"\"\"\n",
    "    # 设置API密钥\n",
    "    DEEPSEEK_API_KEY = \"sk-8d043c487cf04418bbdcf659f052331e\"  # 请替换为你的实际API密钥\n",
    "    \n",
    "    # 创建RAG系统\n",
    "    rag = RAGSystem(DEEPSEEK_API_KEY)  # 初始化RAG系统\n",
    "    \n",
    "    # 示例2: 从文本添加文档\n",
    "    sample_texts = [  # 示例文本列表\n",
    "        \"\"\"\n",
    "        人工智能（AI）是计算机科学的一个分支，致力于创建能够模拟人类智能的系统。\n",
    "        AI系统可以学习、推理、解决问题和理解语言。机器学习是AI的一个重要子领域，\n",
    "        它使计算机能够从数据中学习而无需明确编程。深度学习是机器学习的一个子集，\n",
    "        使用神经网络来模拟人脑的工作方式。\n",
    "        \"\"\",\n",
    "        \"\"\"\n",
    "        自然语言处理（NLP）是人工智能的一个重要分支，专注于让计算机理解、\n",
    "        解释和生成人类语言。NLP的应用包括机器翻译、情感分析、问答系统和\n",
    "        文本摘要。现代NLP系统大多基于深度学习模型，如Transformer架构。\n",
    "        \"\"\",\n",
    "        \"\"\"\n",
    "        计算机视觉是人工智能的另一个重要领域，致力于让计算机能够识别和理解\n",
    "        图像和视频内容。常见的计算机视觉任务包括图像分类、目标检测、\n",
    "        图像分割和人脸识别。卷积神经网络（CNN）是计算机视觉中最常用的模型。\n",
    "        \"\"\"\n",
    "    ]\n",
    "    \n",
    "    # 添加文档到系统\n",
    "    rag.add_documents_from_text(sample_texts)  # 添加示例文本到RAG系统\n",
    "    \n",
    "    # 交互式查询\n",
    "    print(\"=== DeepSeek RAG 系统 ===\")  # 打印系统标题\n",
    "    print(\"输入问题进行查询，输入 'quit' 退出\")  # 打印使用说明\n",
    "    print(\"输入 'clear' 清除对话历史\")  # 打印清除历史说明\n",
    "    print(\"输入 'save' 保存系统状态\")  # 打印保存系统说明\n",
    "    print(\"-\" * 50)  # 打印分隔线\n",
    "    \n",
    "    while True:  # 无限循环\n",
    "        question = input(\"\\n请输入您的问题: \").strip()  # 获取用户输入\n",
    "        \n",
    "        if question.lower() == 'quit':  # 如果输入quit\n",
    "            break  # 退出循环\n",
    "        elif question.lower() == 'clear':  # 如果输入clear\n",
    "            rag.clear_history()  # 清除历史\n",
    "            print(\"对话历史已清除\")  # 打印确认信息\n",
    "            continue  # 继续循环\n",
    "        elif question.lower() == 'save':  # 如果输入save\n",
    "            rag.save_system(\"rag_system.pkl\")  # 保存系统\n",
    "            print(\"系统状态已保存\")  # 打印确认信息\n",
    "            continue  # 继续循环\n",
    "        elif not question:  # 如果输入为空\n",
    "            continue  # 继续循环\n",
    "        \n",
    "        # 查询\n",
    "        print(\"正在查询...\")  # 打印查询状态\n",
    "        result = rag.query(question, use_history=True)  # 执行查询\n",
    "        \n",
    "        # 显示结果\n",
    "        print(f\"\\n回答: {result['answer']}\")  # 打印回答\n",
    "        print(f\"\\n参考了 {result['relevant_documents']} 个相关文档\")  # 打印文档数量\n",
    "        \n",
    "        # 显示来源（可选）\n",
    "        show_sources = input(\"\\n是否显示来源信息? (y/n): \").lower() == 'y'  # 询问是否显示来源\n",
    "        if show_sources:  # 如果用户选择显示\n",
    "            print(\"\\n来源信息:\")  # 打印标题\n",
    "            for i, source in enumerate(result['sources']):  # 遍历来源\n",
    "                print(f\"{i+1}. 文档ID: {source['document_id']}\")  # 打印文档ID\n",
    "                print(f\"   内容预览: {source['content_preview']}\")\n",
    "    print(\"=== DeepSeek RAG 系统 ===\")\n",
    "    print(\"输入问题进行查询，输入 'quit' 退出\")\n",
    "    print(\"输入 'clear' 清除对话历史\")\n",
    "    print(\"输入 'save' 保存系统状态\")\n",
    "    print(\"-\" * 50)\n",
    "    \n",
    "    \n",
    "\n",
    "if __name__ == \"__main__\":\n",
    "    main()"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "使用 sentence-transformers 模型: all-MiniLM-L6-v2\n",
      "正在处理 3 个文档...\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "Batches:   0%|          | 0/1 [00:00<?, ?it/s]"
      ],
      "application/vnd.jupyter.widget-view+json": {
       "version_major": 2,
       "version_minor": 0,
       "model_id": "04e057da40df44829d5e181b521965bf"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "成功添加 3 个文档\n",
      "=== DeepSeek RAG 系统 ===\n",
      "输入问题进行查询，输入 'quit' 退出\n",
      "输入 'clear' 清除对话历史\n",
      "输入 'save' 保存系统状态\n",
      "--------------------------------------------------\n",
      "正在查询...\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "Batches:   0%|          | 0/1 [00:00<?, ?it/s]"
      ],
      "application/vnd.jupyter.widget-view+json": {
       "version_major": 2,
       "version_minor": 0,
       "model_id": "318e26a70cda4be7a416769b87a87c97"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[{'role': 'user', 'content': '你是一个专业的AI助手。请根据以下上下文信息回答用户的问题。\\n\\n上下文信息：\\n文档 1:\\n人工智能（AI）是计算机科学的一个分支，致力于创建能够模拟人类智能的系统。\\n        AI系统可以学习、推理、解决问题和理解语言。机器学习是AI的一个重要子领域，\\n        它使计算机能够从数据中学习而无需明确编程。深度学习是机器学习的一个子集，\\n        使用神经网络来模拟人脑的工作方式。\\n\\n文档 2:\\n计算机视觉是人工智能的另一个重要领域，致力于让计算机能够识别和理解\\n        图像和视频内容。常见的计算机视觉任务包括图像分类、目标检测、\\n        图像分割和人脸识别。卷积神经网络（CNN）是计算机视觉中最常用的模型。\\n\\n文档 3:\\n自然语言处理（NLP）是人工智能的一个重要分支，专注于让计算机理解、\\n        解释和生成人类语言。NLP的应用包括机器翻译、情感分析、问答系统和\\n        文本摘要。现代NLP系统大多基于深度学习模型，如Transformer架构。\\n\\n文档 4:\\n计算机视觉是人工智能的另一个重要领域，致力于让计算机能够识别和理解\\n        图像和视频内容。常见的计算机视觉任务包括图像分类、目标检测、\\n        图像分割和人脸识别。卷积神经网络（CNN）是计算机视觉中最常用的模型。\\n\\n文档 5:\\n计算机视觉是人工智能的另一个重要领域，致力于让计算机能够识别和理解\\n        图像和视频内容。常见的计算机视觉任务包括图像分类、目标检测、\\n        图像分割和人脸识别。卷积神经网络（CNN）是计算机视觉中最常用的模型。\\n\\n\\n用户问题：AI是什么\\n\\n请基于提供的上下文信息给出准确、详细的回答。如果上下文信息不足以回答问题，请说明这一点。\\n\\n回答：'}]\n",
      "\n",
      "回答: 根据提供的上下文信息，人工智能（AI）是计算机科学的一个分支，致力于创建能够模拟人类智能的系统。AI系统具备学习、推理、解决问题和理解语言的能力。其核心特点包括：\n",
      "\n",
      "1. **关键组成部分**  \n",
      "   - **机器学习**：AI的重要子领域，使计算机能够从数据中自主学习而无需显式编程。  \n",
      "   - **深度学习**：机器学习的子集，通过神经网络模拟人脑工作方式（如文档1所述）。\n",
      "\n",
      "2. **主要应用领域**  \n",
      "   - **计算机视觉**：识别和理解图像/视频内容，常用卷积神经网络（CNN），任务包括图像分类、目标检测等（文档2、4、5重复强调）。  \n",
      "   - **自然语言处理（NLP）**：理解、生成人类语言，应用涵盖机器翻译、情感分析等，主流模型如Transformer架构（文档3）。\n",
      "\n",
      "3. **核心目标**  \n",
      "   AI旨在通过模拟人类认知功能（如学习、语言处理、视觉感知）实现自动化决策与复杂任务处理。\n",
      "\n",
      "上下文信息已充分涵盖AI的定义、技术分支及典型应用，无需额外补充。\n",
      "\n",
      "参考了 5 个相关文档\n",
      "\n",
      "来源信息:\n",
      "1. 文档ID: text_0_0\n",
      "   内容预览: 人工智能（AI）是计算机科学的一个分支，致力于创建能够模拟人类智能的系统。\n",
      "        AI系统可以学习、推理、解决问题和理解语言。机器学习是AI的一个重要子领域，\n",
      "        它使计算机能够从数据中学习而无需明确编程。深度学习是机器学习的一个子集，\n",
      "        使用神经网络来模拟人脑的工作方式。\n",
      "2. 文档ID: text_2_0\n",
      "   内容预览: 计算机视觉是人工智能的另一个重要领域，致力于让计算机能够识别和理解\n",
      "        图像和视频内容。常见的计算机视觉任务包括图像分类、目标检测、\n",
      "        图像分割和人脸识别。卷积神经网络（CNN）是计算机视觉中最常用的模型。\n",
      "3. 文档ID: text_1_0\n",
      "   内容预览: 自然语言处理（NLP）是人工智能的一个重要分支，专注于让计算机理解、\n",
      "        解释和生成人类语言。NLP的应用包括机器翻译、情感分析、问答系统和\n",
      "        文本摘要。现代NLP系统大多基于深度学习模型，如Transformer架构。\n",
      "4. 文档ID: text_2_0\n",
      "   内容预览: 计算机视觉是人工智能的另一个重要领域，致力于让计算机能够识别和理解\n",
      "        图像和视频内容。常见的计算机视觉任务包括图像分类、目标检测、\n",
      "        图像分割和人脸识别。卷积神经网络（CNN）是计算机视觉中最常用的模型。\n",
      "5. 文档ID: text_2_0\n",
      "   内容预览: 计算机视觉是人工智能的另一个重要领域，致力于让计算机能够识别和理解\n",
      "        图像和视频内容。常见的计算机视觉任务包括图像分类、目标检测、\n",
      "        图像分割和人脸识别。卷积神经网络（CNN）是计算机视觉中最常用的模型。\n",
      "=== DeepSeek RAG 系统 ===\n",
      "输入问题进行查询，输入 'quit' 退出\n",
      "输入 'clear' 清除对话历史\n",
      "输入 'save' 保存系统状态\n",
      "--------------------------------------------------\n"
     ]
    }
   ],
   "execution_count": 2
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-07-22T08:50:25.586776Z",
     "start_time": "2025-07-22T08:50:25.582093Z"
    }
   },
   "cell_type": "code",
   "source": "16*7.5",
   "id": "8fb249f61eb4eb10",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "120.0"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 3
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-07-22T08:51:12.081611Z",
     "start_time": "2025-07-22T08:51:12.078607Z"
    }
   },
   "cell_type": "code",
   "source": "15+15+12*7.5/64",
   "id": "f1f4268d1fe9ae3e",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "31.40625"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 4
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-07-22T08:51:33.223917Z",
     "start_time": "2025-07-22T08:51:33.220951Z"
    }
   },
   "cell_type": "code",
   "source": "15+14*7.5/64",
   "id": "3eca6ba07a3699aa",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "16.640625"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 5
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-07-22T08:51:58.518993Z",
     "start_time": "2025-07-22T08:51:58.515843Z"
    }
   },
   "cell_type": "code",
   "source": "16*7.5/64",
   "id": "a3c1c5d72d1f9520",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1.875"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 6
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
